package org.givwenzen.builder;



import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Map;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceDelta;
import org.eclipse.core.resources.IResourceDeltaVisitor;
import org.eclipse.core.resources.IResourceVisitor;
import org.eclipse.core.resources.IncrementalProjectBuilder;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jdt.internal.core.ResolvedSourceMethod;
import org.givwenzen.markers.MarkerTool;
import org.givwenzen.steps.LineParser;
import org.givwenzen.steps.StepLocator;

public class GivWenZenValidator extends IncrementalProjectBuilder {

    MarkerTool markerTool = new MarkerTool();
    
	public static class StepUse {

        final String step;
        final IFile file;

        public StepUse(String step, IFile file) {
            this.step = step;
            this.file = file;
        }

        @Override
        public int hashCode() {
            final int prime = 31;
            int result = 1;
            result = prime * result + ((file == null) ? 0 : file.hashCode());
            result = prime * result + ((step == null) ? 0 : step.hashCode());
            return result;
        }

        @Override
        public boolean equals(Object obj) {
            if (this == obj)
                return true;
            if (obj == null)
                return false;
            if (getClass() != obj.getClass())
                return false;
            StepUse other = (StepUse) obj;
            if (file == null) {
                if (other.file != null)
                    return false;
            } else if (!file.equals(other.file))
                return false;
            if (step == null) {
                if (other.step != null)
                    return false;
            } else if (!step.equals(other.step))
                return false;
            return true;
        }
    }

    class SampleDeltaVisitor implements IResourceDeltaVisitor {
        /*
		 * (non-Javadoc)
		 * 
		 * @see org.eclipse.core.resources.IResourceDeltaVisitor#visit(org.eclipse.core.resources.IResourceDelta)
		 */
		public boolean visit(IResourceDelta delta) throws CoreException {
			IResource resource = delta.getResource();
			switch (delta.getKind()) {
			case IResourceDelta.ADDED:
				// handle added resource
				checkSteps(resource, null);
				break;
			case IResourceDelta.REMOVED:
				// handle removed resource
				break;
			case IResourceDelta.CHANGED:
				// handle changed resource
				checkSteps(resource, null);
				break;
			}
			//return true to continue visiting children.
			return true;
		}
	}

	class SampleResourceVisitor implements IResourceVisitor {

        private final IProgressMonitor monitor;

        public SampleResourceVisitor(IProgressMonitor monitor) {
            this.monitor = monitor;
        }

        public boolean visit(IResource resource) {
			checkSteps(resource, monitor);
			//return true to continue visiting children.
			return true;
		}
	}

	public static final String BUILDER_ID = "GivWenZenclipse.GivWenZenValidator";

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.core.internal.events.InternalBuilder#build(int,
	 *      java.util.Map, org.eclipse.core.runtime.IProgressMonitor)
	 */
	protected IProject[] build(int kind, Map args, IProgressMonitor monitor)
			throws CoreException {
		if (kind == FULL_BUILD) {
			fullBuild(monitor);
		} else {
			IResourceDelta delta = getDelta(getProject());
			if (delta == null) {
				fullBuild(monitor);
			} else {
				incrementalBuild(delta, monitor);
			}
		}
		return null;
	}

	void checkSteps(IResource resource, IProgressMonitor monitor) {	  
      if (resource instanceof IFile && resource.getName().endsWith("content.txt")) {
            IFile file = (IFile) resource;
            markerTool.deleteMarkers(file);
            
            BufferedReader br = null;
            try {
                br = new BufferedReader(new InputStreamReader(file.getContents()));
                String line = br.readLine();
                int lineNo = 0;
                while (line != null) {
                    lineNo++;
                    LineParser lineParser = new LineParser();
                    if (lineParser.isStep(line)) {
                        String step = lineParser.parse(line);
                        if (monitor != null) {
                            monitor.subTask("Validating step: " + step);
                            monitor.worked(1);
                        }
                        ResolvedSourceMethod stepImplementation = validateStep(step, resource.getProject());
                        if (stepImplementation == null) {                            
                            markerTool.drawMarker(file, step, lineNo);
                        }
                    }
                    line = br.readLine();
                }
            } catch (Exception e) {
                throw new RuntimeException(e);
            } finally {
                if (br != null)
                    try {
                        br.close();
                    } catch (Exception e) {}
            }
        }
	}

    private ResolvedSourceMethod validateStep(String step, IProject iProject) {
        return new StepLocator().findMethod(step, iProject);        
    }

	protected void fullBuild(final IProgressMonitor monitor)
			throws CoreException {
		try {
		    //TODO no. of steps is hardcoded to 20
		    if (monitor != null) monitor.beginTask("Started validating steps...", 20);
			getProject().accept(new SampleResourceVisitor(monitor));
		} catch (CoreException e) {
		}
	}

	protected void incrementalBuild(IResourceDelta delta,
			IProgressMonitor monitor) throws CoreException {
		// the visitor does the work.
		delta.accept(new SampleDeltaVisitor());
	}
}
